from selenium.webdriver.support.select import Select
import time,os,sys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

from utils.readConfigUtils import readConfig

#页面基类
#把每个页面都需要的一些通用的操作封装起来
class PageBase(object):
    def __init__(self,driver,base_url):
        self.driver=driver
        self.base_url=base_url

    def make_xpath_with_unit_feature(self, loc):
        args = loc.split(",")
        feature = ""  # 返回值

        if len(args) == 2:
            feature = "contains(@" + args[0] + ",'" + args[1] + "')" + "and "
        elif len(args) == 3:
            if args[2] == "1":
                feature = "@" + args[0] + "='" + args[1] + "'" + "and "
            elif args[2] == "0":
                feature = "contains(@" + args[0] + ",'" + args[1] + "')" + "and "
        return feature

    '''
    函数功能：给简化的xpath，函数返回标准的xpath字符串。
    即:
    如果loc = "text,设置"或"text,设置,0"，函数返回"//*[contains(@text,'设置')]"，情况1。
    如果loc = "text,设置,1"，函数返回"//*[@text='设置']"，情况2。
    如果loc = ["text,设置"] ，函数返回"//*[contains(@text,'设置')]"，情况1。
    如果loc = ["text,设置", "index,20,1", "index1,50"]，函数返回"//*[contains(@text,'设置')and@index='20'andcontains(@index1,'50')]"，情况3。
    如果loc = "//*[contains(@text,'设')]" ，即故意传个正常的xpath字符串，函数返回"//*[contains(@text,'设')]"，情况4。
    '''

    def make_xpath_with_feature(self, loc):
        feature_start = "//*["
        feature_end = "]"
        feature = ""

        # 如果传的是字符串，即情况1和情况2
        if isinstance(loc, str):
            # 如果是正常的xpath，即情况4
            if loc.startswith("//"):
                return loc
            feature = self.make_xpath_with_unit_feature(loc)
        else:  # 如果传的是列表，即情况3
            for i in loc:
                feature += self.make_xpath_with_unit_feature(i)

        feature = feature.rstrip("and ")  # 删除最右侧的"and "
        ret_loc = feature_start + feature + feature_end
        return ret_loc

    def find_element(self,loc):
        by=loc[0]
        value=loc[1]
        if by==By.XPATH:
            value=self.make_xpath_with_feature(value)
        return self.driver.find_element(by,value)

    def find_elements(self, loc):
        by = loc[0]
        value = loc[1]
        if by == By.XPATH:  # 如果定位是XPATH定位，可以简化
            value = self.make_xpath_with_feature(value)
        return self.driver.find_elements(by, value)

    def open(self,pathUrl):#类似"/webzdh/form.html"
        self.driver.get(self.base_url+pathUrl)

    #对文本框/密码框/多行文本框输入数据
    def input(self,loc,data):
        self.find_element(loc).send_keys(data)

    #对文本框/密码框/多行文本框进行清空并输入数据：不会触发鼠标失去焦点事件
    def clearAndInput(self,loc,data):
        ele = self.find_element(loc)
        ele.send_keys(Keys.CONTROL, 'a')
        ele.send_keys(Keys.BACK_SPACE)
        ele.send_keys(data)

    # 清空文本框/密码框/多行文本框（会让鼠标失去焦点，触发前端的失去焦点）
    def clear(self, loc):
        self.find_element(loc).clear()

    # 获取文本框/密码框/多行文本框的的用户输入数据
    def getUserData(self, loc):
        return self.find_element(loc).get_attribute("value")

    #点击按钮类、超链接a标签
    def click(self, loc):
        self.find_element(loc).click()

    # 单选按钮控件：选中某选项
    def selectRaidoOption(self, attr_name, selectOptionValue):
        self.driver.find_element_by_css_selector(f"input[type='radio'][name='{attr_name}'][value='{selectOptionValue}']").click()

    # 单选按钮控件：获取用户选中的那个选项的value属性的值
    def getUserDataRaido(self, attr_name):
        eles = self.driver.find_elements_by_css_selector(f"input[type='radio'][name='{attr_name}']")
        for ele in eles:
            selectStatus = ele.is_selected()
            if selectStatus:
                return ele.get_attribute("value")
        return None

    # 复选框控件：选中0个/1个或N个选项。
    def selectCheckBoxOptions(self, attr_name, selectOptionsValues):
        allOption = self.driver.find_elements_by_css_selector(f"input[type='checkbox'][name='{attr_name}']")
        for one in allOption:
            attr_value = one.get_attribute("value")
            selectStatus = one.is_selected()  # 获取该选项的原始选中状态
            if attr_value in selectOptionsValues:  # 该选项确保选中
                if selectStatus:
                    pass
                else:
                    one.click()
            else:  # 该选项确保不选中
                if selectStatus:
                    one.click()
                else:
                    pass

    # 复选框：获取用户选中的选项们的value属性的值
    def getUserDataCheckBox(self, attr_name):
        allOption = self.driver.find_elements_by_css_selector(f"input[type='checkbox'][name='{attr_name}']")
        userData = ""
        for one in allOption:
            selectStatus = one.is_selected()
            if selectStatus:
                attrValue = one.get_attribute("value")
                userData += attrValue + ","

        return userData[0:-1]

    # 下拉列表控件：选中某选项
    def selectSelectOption(self, attr_name, selectOptionText):
        select = Select(self.driver.find_element_by_css_selector(f"select[name='{attr_name}']"))
        select.select_by_visible_text(selectOptionText)  # 推荐

    # 下拉列表控件：获取用户选中的选项的文本内容
    def getUserDataSelect(self, attr_name):
        select = Select(self.driver.find_element_by_css_selector(f"select[name='{attr_name}']"))
        selectOption = select.first_selected_option
        return selectOption.text

    # 日期控件：获取用户设置的日期值
    def getUserDataDate(self, loc):
        ele = self.find_element(loc)
        return ele.get_attribute("value")

    # 文件框：上传1个或N个文件/文件夹：实现方法1
    def uploadFiles1(self, loc_file, filePaths):
        if "," in filePaths:  # 如果是上传多个
            filePaths = filePaths.replace(",", "\n")
            self.find_element(loc_file).send_keys(filePaths)
        else:  # 如果是上传1个
            self.find_element(loc_file).send_keys(filePaths)

    # 文件框：上传1个或N个文件/文件夹：实现方式2：autoIT（通用版）
    def uploadFiles2(self, loc_file, filePaths):
        ele_file = self.find_element(loc_file)
        ActionChains(self.driver).click(ele_file).perform()

        time.sleep(2)

        files = filePaths.split(",")  # ['C:/A/1.png', 'C:/A/2.png']
        ret = ""
        for x in files:  # x="C:/A/1.png"
            ret += '"' + x + '" '
        ret = ret.replace("/", "\\")

        uploadFilesPath=os.getcwd()+"/"+readConfig("config/toolsPath.yaml")["uploadFilePath"]
        os.system(f'{uploadFilesPath} {ret}')

    # 处理JS三种弹出框
    # 获取三种JS弹出框的文本内容
    def getTextForJsTanCuKuan(self):
        return self.driver.switch_to.alert.text

    # 点击三种JS弹出框的“确定”按钮
    def acceptForJsTanCuKuan(self):
        self.driver.switch_to.alert.accept()

    # 点击三种JS弹出框的“取消”按钮
    def dismissForJsTanCuKuan(self):
        self.driver.switch_to.alert.dismiss()

    # 为JS的prompt弹出框输入文本
    def inputJsTanCuKuan(self, data):
        self.driver.switch_to.alert.send_keys(data)

    # 获取元素loc的某属性attr的值
    def getAttr(self, loc, attr):
        return self.find_element(loc).get_attribute(attr)

    # 获取某元素loc的文本内容
    def getText(self, loc):
        return self.find_element(loc).text

    # iframe框架相关处理
    # 切换到某iframe
    def switch_iframe(self, loc_iframe):
        ele_ifame = self.find_element(loc_iframe)
        self.driver.switch_to.frame(ele_ifame)

    # 切换到主iframe
    def switch_defaultIframe(self):
        self.driver.switch_to.default_content()

    # 切换标签页/切换窗口
    # 形参n是第几个窗口。n从0开始.-1：最新打开窗口
    def switch_windowByIndex(self, n):
        self.driver.switch_to.window(self.driver.window_handles[n])

    #根据窗口标题（可以给部分）来切换到对应的窗口
    def switch_windowByTitle(self,target_title):
        allWindows = self.driver.window_handles
        for one in allWindows:
            self.driver.switch_to.window(one)
            currentTitle = self.driver.title
            if target_title in currentTitle:
                break
            time.sleep(1)

    # 鼠标操作的相关处理

    # 函数功能：鼠标单击某元素loc
    def mouse_click(self, loc):
        ele = self.find_element(loc)
        ActionChains(self.driver).click(ele).perform()

    # 函数功能：鼠标双击某元素loc
    def mouse_dbclick(self, loc):
        ele = self.find_element(loc)
        ActionChains(self.driver).double_click(ele).perform()

    # 函数功能：鼠标悬停在某元素loc
    def mouse_moveToEle(self, loc):
        ele = self.find_element(loc)
        ActionChains(self.driver).move_to_element(ele).perform()

    # 函数功能：滑动垂直滚动条到最底部
    def scrollToFloor(self):
        js1 = "window.scrollTo(0,10000)"
        self.driver.execute_script(js1)

    # 网页截图
    def savePng1(self, filePath):
        self.driver.get_screenshot_as_file(filePath)

    def savePng2(self, fileName):
        self.driver.get_screenshot_as_file("./screen/" + fileName + ".png")

    def savePng3(self, serviceName, key):
        fileName = serviceName + "_" + key + "_" + time.strftime("%Y%m%d%H%M%S")
        self.driver.get_screenshot_as_file("./screen/" + fileName + ".png")
        return fileName


